home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / Winter Shell 1.0d2 / Source / Libraries / FileLib / FileIOLib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-08  |  7.1 KB  |  238 lines  |  [TEXT/KAHL]

  1. /* Functions for reading from and writing to files. For files opened
  2.     with fsRdWrShPerm there are functions which implement range locking.
  3.     You can also specify that the area being written to or read from be
  4.     automatically locked while writing (or reading) and unlocked when
  5.     finished writing (or reading). For writing, you can enable automatic
  6.     verfication, so that a read verify operation will be performed after
  7.     each write. A few of the functions are slightly inefficient: before
  8.     every operation the entire parameter block is cleared with a call
  9.     to memclr, even though only a few fields may actually need to be
  10.     cleared. However, in the interests of correctness, I decided to
  11.     retain the calls to memclr.
  12.  
  13.     Revision History:
  14.     
  15.     93/03/23 AIH
  16.     - Made buffer parameters to file writing functions const
  17.     
  18.     91/11/14 AIH
  19.     - Removed checks for system software prior to version 7.0
  20.     
  21.     91/06/13 AIH
  22.     - Time library is used to delay so that background tasks get time
  23.     
  24.     91/05/31 AIH
  25.     - Added assertion to prevent a bug with _PBLockRange in system software
  26.     6.0.7 and earlier. This bug is documented in TN186.
  27.     
  28.     91/05/16 AIH
  29.     - Added a few comments
  30.     
  31.     91/04/20 Ari Halberstadt (AIH)
  32.     - Added automatic write verify function */
  33.     
  34. #include <limits.h>
  35. #include <string.h>
  36. #include "MacLib.h"
  37. #include "MemoryLib.h"
  38. #include "TimeLib.h"
  39. #include "StringLib.h"
  40. #include "TimeLib.h"
  41. #include "FileLib.h"
  42.  
  43. /*----------------------------------------------------------------------------*/
  44. /* locking and unlocking ranges */
  45. /*----------------------------------------------------------------------------*/
  46.  
  47. /* turn automatic range locking on or off */
  48. void FileAutoLockSet(FileType *fp, Boolean lock)
  49. {
  50.     fp->lock = lock;
  51. }
  52.  
  53. /* lock count bytes following the specified position */
  54. void FileRangeLock(FileType *fp, FilePosType count, FilePosType pos)
  55. {
  56.     const TicksType wait = 5;    /* ticks to wait after each failure */
  57.     const short maxtry = 6;        /* maximum number of attempts to lock range */
  58.     volatile short try = 0;        /* number of attempts to lock the range */
  59.     ParamBlockRec pb;
  60.     
  61.     require(FileValid(fp));
  62.     require(fp->ref != FILE_CLOSED);
  63.     TRY {
  64.         /* Try to lock the range. After each failure, wait several ticks
  65.             before trying again. Give up after too many failures. */
  66.         memclr(&pb, sizeof(ParamBlockRec));
  67.         pb.ioParam.ioRefNum = fp->ref;
  68.         pb.ioParam.ioReqCount = count;
  69.         pb.ioParam.ioPosMode = fsFromStart;
  70.         pb.ioParam.ioPosOffset = pos;
  71.         FailOSErr(PBLockRange(&pb, false));
  72.     } CATCH {
  73.         if (++try < maxtry) {
  74.             TimeDelay(wait);
  75.             RETRY;
  76.         }
  77.     } ENDTRY;
  78. }
  79.  
  80. /* unlock count bytes following the specified position */
  81. void FileRangeUnlock(FileType *fp, FilePosType count, FilePosType pos)
  82. {
  83.     ParamBlockRec pb;
  84.     
  85.     require(FileValid(fp));
  86.     require(fp->ref != FILE_CLOSED);
  87.     memclr(&pb, sizeof(ParamBlockRec));
  88.     pb.ioParam.ioRefNum = fp->ref;
  89.     pb.ioParam.ioReqCount = count;
  90.     pb.ioParam.ioPosMode = fsFromStart;
  91.     pb.ioParam.ioPosOffset = pos;
  92.     FailOSErr(PBUnlockRange(&pb, false));
  93. }
  94.  
  95. /*----------------------------------------------------------------------------*/
  96. /* write verification */
  97. /*----------------------------------------------------------------------------*/
  98.  
  99. /* turn automatic write verification on or off */
  100. void FileVerifySet(FileType *fp, Boolean verify)
  101. {
  102.     fp->verify = verify;
  103. }
  104.  
  105. /*----------------------------------------------------------------------------*/
  106. /* reading and writing */
  107. /*----------------------------------------------------------------------------*/
  108.  
  109. /* this is very similar to FSRead */
  110. FilePosType FileRead(FileType *fp, FilePosType count, void *buffer)
  111. {
  112.     OSErr err;
  113.     
  114.     require(FileValid(fp));
  115.     require(fp->ref != FILE_CLOSED);
  116.     require(count >= 0);
  117.     err = FSRead(fp->ref, &count, buffer);
  118.     if (err == eofErr)
  119.         err = noErr;
  120.     FailOSErr(err);
  121.     return(count);
  122. }
  123.  
  124. /* This is very similar to FSWrite. If the file's lock attribute is set then
  125.     the range to be read is locked and then unlocked. If the file's verify
  126.     attribute is set then the write is verified. */
  127. void FileWrite(FileType *fp, FilePosType count, const void *buffer)
  128. {
  129.     volatile FilePosType    pos;        /* current position in file */
  130.     volatile Boolean        locked;    /* true if we did range locking */
  131.     FilePosType actcnt;    /* actual number of bytes written */
  132.     ParamBlockRec pb;        /* for verifying the write */
  133.     OSErr err = noErr;
  134.     
  135.     require(FileValid(fp));
  136.     require(fp->ref != FILE_CLOSED);
  137.     require(count >= 0);
  138.     TRY {
  139.         /* lock the range if auto-locking is enabled */
  140.         locked = false;
  141.         if (fp->lock) {
  142.             pos = FilePosition(fp);
  143.             FileRangeLock(fp, count, pos);
  144.             locked = true;
  145.         }
  146.         /* write */
  147.         actcnt = count;
  148.         FailOSErr(FSWrite(fp->ref, &actcnt, (Ptr) buffer));
  149.         check(actcnt == count);
  150.         if (fp->verify) {
  151.             /* verify write */
  152.             memclr(&pb, sizeof(ParamBlockRec));
  153.             pb.ioParam.ioRefNum = fp->ref;
  154.             pb.ioParam.ioBuffer = (void *) buffer;
  155.             pb.ioParam.ioReqCount = count;
  156.             pb.ioParam.ioPosMode = rdVerify;
  157.             err = PBRead(&pb, false);
  158.             if (err == eofErr) /* reaching the eof on a read isn't an error */
  159.                 err = noErr;
  160.             FailOSErr(err);
  161.         }
  162.     } CLEANUP {
  163.         if (locked)
  164.             FileRangeUnlock(fp, count, pos);
  165.     } ENDTRY;
  166. }
  167.  
  168. /*----------------------------------------------------------------------------*/
  169. /* reading and writing a single character (not very efficient) */
  170. /*----------------------------------------------------------------------------*/
  171.  
  172. /* read one character from the file */
  173. Boolean FileReadChar(FileType *fp, char *c)
  174. {
  175.     return(FileRead(fp, 1, c) == 1);
  176. }
  177.  
  178. /* write one character to the file */
  179. void FileWriteChar(FileType *fp, char c)
  180. {
  181.     FileWrite(fp, 1, &c);
  182. }
  183.  
  184. /*----------------------------------------------------------------------------*/
  185. /* reading and writing strings */
  186. /*----------------------------------------------------------------------------*/
  187.  
  188. /* Read a string terminated with the 'stop' character from the file.
  189.     At most 'count' characters are read, and the terminating character
  190.     is discarded. The resulting string is null terminated. The
  191.     length of the string is returned (ie, number of
  192.     characters read minus 1). */
  193. FilePosType FileReadStr(FileType *fp, FilePosType count, char *str, char stop)
  194. {
  195.     ParamBlockRec pb;
  196.     Boolean result = false;
  197.     OSErr err = noErr;
  198.     
  199.     require(FileValid(fp));
  200.     require(fp->ref != FILE_CLOSED);
  201.     require(count >= 0);
  202.     /* IM-IV, p121 describes the flags to ioPosMode */
  203.     pb.ioParam.ioCompletion = 0;
  204.     pb.ioParam.ioRefNum = fp->ref;
  205.     pb.ioParam.ioBuffer = str;
  206.     pb.ioParam.ioReqCount = count;
  207.     pb.ioParam.ioPosMode = (fsAtMark | 0x80 | (stop << CHAR_BIT));
  208.     pb.ioParam.ioPosOffset = 0;
  209.     err = PBRead(&pb, false);
  210.     if (err == eofErr)
  211.         err = noErr;
  212.     FailOSErr(err);
  213.     count = pb.ioParam.ioActCount;
  214.     str[pb.ioParam.ioActCount] = 0;
  215.     ensure(strlen(str) == count + 1);
  216.     return(count);
  217. }
  218.  
  219. /* write the null terminated string to the file */
  220. void FileWriteStr(FileType *fp, const char *str)
  221. {
  222.     FileWrite(fp, strlen(str), str);
  223. }
  224.     
  225. /* read a line with at most 'count' characters from the file */
  226. FilePosType FileReadLine(FileType *fp, FilePosType count, char *line)
  227. {
  228.     return(FileReadStr(fp, count, line, '\r'));
  229. }
  230.  
  231. /* flush the volume on which the file resides */
  232. void FileFlush(FileType *fp)
  233. {
  234.     require(FileValid(fp));
  235.     FailOSErr(FlushVol((StringPtr) "", fp->vol));
  236. }
  237.  
  238.